#pragma once

#include<funcitonal>
#include<iostream>
#include<cerrno>
#include<unistd.h>
#include<cstdlib>
#include<cstring>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#include"err.hpp"
namespace nt_server
{       
   

    class UdpServer
    {
        const uint16_t default_port=8888;//后续要服务端要绑定的端口号
        using func_t =std::function<std::string(std::string)>;

    public:
        UdpServer(const func_t& func,uint16_t port=default_port)
        :_serverHand(func)
        ,_port(port)
        {

        }
        
        ~UdpServer(){

        }

        void InitServer()
        {
            //1.创建套接字，成功返回文件描述符位置，失败返回-1
            _sock=socket(AF_INET,SOCK_DGRAM,0);//网络通信，udp协议

            if(_sock==-1)
            {
                std::cout<<"Create Socket Fail"<<strerror(errno)<<std::endl;
                exit(SOCKET_ERR);
            }

            std::cout<<"Create Socket Success:"<<_sock<<std::endl;

            //2.绑定IP地址和端口号
            struct sockaddr_in local;
            bzero(&local,sizeof(local));

            //填充字段
            local.sin_family=AF_INET;//设置为网络通信
            local.sin_port=htons(_port);//将uint16_t整形的主机序列转成网络序列
            //local.sin_addr.s_addr=inet_addr(_ip.c_str());//将点分十进制的字符串形式的主机序列转成网络序列
            local.sin_addr.s_addr=INADDR_ANY;

            //成功返回0，失败返回-1
            if(bind(_sock,(struct sockaddr*)&local,sizeof(local)))
            {
                std::cout<<"Bind IP&&Port Fail:"<<strerror(errno)<<std::endl;
                exit(BIND_ERR);
            }
            
            std::cout<<"Bind IP&&Port Success"<<std::endl;
        }

        void StartServer()
        {
            char buff[1024];
            while(true)
            {
                //1.接受消息
                struct sockaddr_in peer;//客户端结构体 
                socklen_t len=sizeof(peer);//客户端结构体大小

                //成功返回缓冲区大小，失败返回0
                ssize_t n=recvfrom(_sock,buff,sizeof(buff)-1,0,(struct sockaddr*)&peer,&len);
                
                if(n>0)
                    buff[n]='\0';
                else
                    continue;

                //2.处理数据对端ip和端口号
                std::string clientIp=inet_ntoa(peer.sin_addr);
                uint16_t clientPort=ntohs(peer.sin_port);
                printf("Server get message from [%c:%d]$ %s\n",clientIp.c_str(),clientPort,buff);
            
                //3.回响消息给客户端
                //成功返回实际发送字节数，失败返回-1
                n=sendto(_sock,buff,strlen(buff),0,(const struct sockaddr*)&peer,sizeof(peer));
            
                if(n==-1)
                    std::cout<<"Send Message Fail:"<<strerror(errno)<<std::endl;
            }
        }
    private:
        int _sock;//套接字（文件描述符）
        uint16_t _port;//端口号
        //std::string _ip;//IP地址
        func_t _serverHandle;
    };

    
}